﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


using FXnaEngine.Interfaces;

using FXnaEngine.Components;

using FXnaEngine.Physics;



using FXnaEngine.Input;



namespace FXnaEngine.Graphics
{
   public class FGraphicsSystem
    {

       public FGraphicsSystem(FGame game)
       {

           this.game = game;

           this.game.GameMessage += new EngineMessageHandler(game_GameMessage);



           //这里需要认真考虑


           FEngineState.GraphicsDeviceService.DeviceReset += new EventHandler<EventArgs>(GraphicsDeviceService_DeviceReset);

           //FEngineState.GraphicsDeviceService.DeviceCreated += new EventHandler<EventArgs>(GraphicsDeviceService_DeviceCreated);



           //不能保证这个时候的device是否存在啊，以及重置之后，这些可能都要变化




           shaderBasic = new FBasicSE();


           sceneRenderTarget = new RenderTarget2D(this.game.GraphicsDevice, this.game.GraphicsDevice.PresentationParameters.BackBufferWidth, this.game.GraphicsDevice.PresentationParameters.BackBufferHeight, true, SurfaceFormat.Rgba64, DepthFormat.Depth24Stencil8);



           spriteBatch = new SpriteBatch(this.game.GraphicsDevice);


        
           



        





           rendererlist = new List<FRendererComponent>();








          










       }

       void GraphicsDeviceService_DeviceCreated(object sender, EventArgs e)
       {

           shaderBasic = new FBasicSE();


           sceneRenderTarget = new RenderTarget2D(this.game.GraphicsDevice, this.game.GraphicsDevice.PresentationParameters.BackBufferWidth, this.game.GraphicsDevice.PresentationParameters.BackBufferHeight, true, SurfaceFormat.Rgba64, DepthFormat.Depth24Stencil8);



           spriteBatch = new SpriteBatch(this.game.GraphicsDevice);


       }


       /// <summary>
       /// 处理设备变化
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
       void GraphicsDeviceService_DeviceReset(object sender, EventArgs e)
       {

           shaderBasic = new FBasicSE();


           sceneRenderTarget = new RenderTarget2D(this.game.GraphicsDevice, this.game.GraphicsDevice.PresentationParameters.BackBufferWidth, this.game.GraphicsDevice.PresentationParameters.BackBufferHeight, true, SurfaceFormat.Rgba64, DepthFormat.Depth24Stencil8);



           spriteBatch = new SpriteBatch(this.game.GraphicsDevice);

           
       }






       void game_GameMessage(IMessage message)
       {
          

       }


    


       FGame game;


       RenderTarget2D sceneRenderTarget;
       RenderTarget2D shadowMapTarget;

       protected RenderTarget2D uiRenderTarget;



       SpriteBatch spriteBatch;  //通用绘图系统


     
       FCameraComponent currentCamera;


       /// <summary>
       /// 当前渲染相机
       /// </summary>
       public FCameraComponent CurrentCamera
       {
           get { return currentCamera; }
          
       }


       /// <summary>
       /// 当前设备
       /// </summary>
       public GraphicsDevice GraphicsDevice
       {

           get {

               return this.game.GraphicsDevice;
           }

       }



       FBasicSE shaderBasic;

       public FBasicSE ShaderBasic
       {
           get { return shaderBasic; }
          
       }




     



 

       //测试

       List<FRendererComponent> rendererlist;

      


       bool enableShadowMapping = false;

       /// <summary>
       /// 是否启用阴影
       /// </summary>
       public bool EnableShadowMapping
       {
           get { return enableShadowMapping; }
           set { enableShadowMapping = value; }
       }



       public void LoadContent()
       { 


     

       
       
       }



       public void Update(GameTime time)
       {
          

         
         
 


       }







           /// <summary>
        /// Draws a single frame.
        /// </summary>
        /// <param name="camera">Entity that will be serving as the camera.</param>
        /// <param name="gameTime">Snapshot of the game timers.</param>
       public void DrawFrame(Entity camera, GameTime gameTime)
       {

           //第一步取得相机的位置,进行第一步的无相机系统的测试，逐渐搭载各个模块，先从小的循环开始




           this.currentCamera = this.game.SceneManager.GetMainCameraEntity().GetComponentByType(typeof(FCameraComponent)) as FCameraComponent; 


           //这里我们暂时更新一下相机的位置给basicEffectShader



           FEngineState.ViewMatrix = this.currentCamera.ViewMatrix;

           FEngineState.ProjectionMatrix = this.currentCamera.projectionMatrix;



           //开始寻找可供渲染的模块

           this.game.SceneManager.MainScene.GetRendererComponents(ref this.rendererlist);


           
           
         


           this.DrawSceneToTarget();


           this.DrawToScreen();



           //清空渲染组件

           this.rendererlist.Clear();




       }


       //public void RenderWithEffect(List<FMesh> meshes, Effect effect)
       //{


 
       //}


       /// <summary>
       /// 对外提供的辅助绘制函数，方便集体调用
       /// </summary>
       /// <param name="mesh"></param>
       /// <param name="effect"></param>
       public void RenderWithEffect(FMesh mesh, Effect effect)
       {

           GraphicsDevice gd = FEngineState.Device;

           gd.SetVertexBuffer(mesh.VertexBuffer);
           gd.Indices = mesh.IndexBuffer;



           foreach (EffectPass pass in effect.CurrentTechnique.Passes)
           {

               pass.Apply();

               pass.Apply();

               gd.DrawIndexedPrimitives(mesh.PrimitiveType, 0, 0, mesh.NumberOfVertices, 0, mesh.NumberOfPrimitives);




               
           }
 
       }



       /// <summary>
       /// 渲染三维场景，
       /// </summary>
       protected void RenderScene()
       {

           //提取相机的状态


           if (this.enableShadowMapping)
           {

               this.RenderShadows();
               
           }


           this.RenderGeometries();




       }


      
       /// <summary>
       /// 阴影渲染模式
       /// </summary>
       protected void RenderShadows()
       {
 
       }



       /// <summary>
       /// 执行实体的渲染工作
       /// </summary>
       protected void RenderGeometries()
       {


           foreach (FRendererComponent item in this.rendererlist)
           {

               item.Render(this);


               
           }

 

       }


       /// <summary>
       /// 将场景渲染到rendertarget,目前处于测试模式
       /// </summary>
       protected void DrawSceneToTarget()
       {


           // Restore z buffer state
           this.game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

           this.game.GraphicsDevice.BlendState = BlendState.AlphaBlend;

           this.game.GraphicsDevice.RasterizerState = RasterizerState.CullNone;



           this.game.GraphicsDevice.SetRenderTarget(sceneRenderTarget);




           this.game.GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Target, Color.Transparent, 1, 0);



           this.RenderScene();




         



  



       }







      


    

       protected void DrawToScreen()
       {



           // Switch back to drawing onto the back buffer
           this.game.GraphicsDevice.SetRenderTarget(null);

           // Now that we're back to drawing onto the back buffer, we want to clear it. If we had done so earlier
           // then when we switched to drawing to the render target, the old back buffer would've just be filled with
           // that bright purple color when we came back to it.
          this.game.GraphicsDevice.Clear(Color.CornflowerBlue);



           float scale = 1.0f;

           // Start spriteBatch again (this time drawing to the back buffer)
           spriteBatch.Begin();

           // Now we draw our render target to the back buffer so that it will get displayed on the screen. We
           // position it in the center of the screen, but we make the origin be the center of the render target
           // such that it actually gets drawn centered (as opposed to shrinking and exanding with the left corner
           // in the center). We use our scale computation, and specify no SpriteEffects and an unused 0f for layer
           // depth
           spriteBatch.Draw(sceneRenderTarget,
               new Vector2(this.game.GraphicsDevice.PresentationParameters.BackBufferWidth / 2,this.game.GraphicsDevice.PresentationParameters.BackBufferHeight / 2),
               null, Color.White, 0f, new Vector2(sceneRenderTarget.Width / 2, sceneRenderTarget.Height / 2), scale,
               SpriteEffects.None, 0f);

           // End our spriteBatch call.
           spriteBatch.End();


 


       }





    }


}
